package cz.cvut.fel.y36mm1.videostreaming.client;

import cz.cvut.fel.y36mm1.videostreaming.Commander;
import cz.cvut.fel.y36mm1.videostreaming.MainMidlet;
import cz.cvut.fel.y36mm1.videostreaming.exceptions.ServerEndedConnectionException;
import cz.cvut.fel.y36mm1.videostreaming.exceptions.CannotConnectToServerException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.VideoControl;

/**
 * Trida reprezentujici klienta. Snima snapshoty a odesila je serveru.
 *
 * @author Jiri Masek, masekj5
 */
public class Client {

	/*
	 * if manual snapshot sending is desired, change this to false.
	 * No other changes of code are necessary
	 */
	private static final boolean AUTOSNAPS = true;
	private CommandListener commandListener;
	private String serverAddress = null;
	private VideoCanvas videoCanvas;
	protected Player player;
	private StreamConnection connection;
	private OutputStream output;
	private InputStream input;
	private VideoControl videoControl;

    /**
     * Vytvori novou instanci tridy <code>Client</code>.
     *
     * @param serviceURL            adresa serveru
     * @param commandListener       Command Listener
     */
	public Client(String serviceURL, CommandListener commandListener) {
		this.commandListener = commandListener;
		serverAddress = serviceURL;
		videoCanvas = new VideoCanvas();
	}

    /**
     * Navaze spojeni se serverem.
     *
     * @throws cz.cvut.fel.y36mm1.videostreaming.exceptions.CannotConnectToServerException
     */
	public void startConnection() throws CannotConnectToServerException {
		try {
			connection = (StreamConnection) Connector.open(serverAddress);
			output = connection.openOutputStream();
			input = connection.openInputStream();
		} catch (IOException ex) {
			throw new CannotConnectToServerException();
		}

		(new CameraThread()).start();
	}

    /**
     *
     * @return
     */
	public Displayable getVideoCanvas() {
		return videoCanvas;
	}

    /**
     * Metoda volani pri ukonceni cinnosti serveru.
     */
	public void serverTerminated() {
		      System.err.println("Server was terminated.");
	}

    /**
     * Odesle snapshot serveru.
     *
     * @param image     snapshot
     */
	public void sendData(byte[] image) {
		try {
			output.write(4);
			output.write(MainMidlet.intToByteArray(image.length));
			output.write(image);

		} catch (IOException ex) {
			System.err.println("IOException: " + ex.getMessage());
		}
	}

	/**
	 * Zastavi a ukonci <code>Player</code>.
	 **/
	public void releaseResources() {
		if (player != null) {
			try {
				player.stop();
				player.close();
			} catch (MediaException ex) {
				ex.printStackTrace();
			}
		}
	}

    /**
     * Ukonci cinnost klienta.
     */
	public void terminateClient() {
		releaseResources();
	}

    /**
     * Inicializuje vsechny potrebne komponenty a zahaji automaticke odesilani
     * snapshotu serveru.
     *
     * @throws cz.cvut.fel.y36mm1.videostreaming.exceptions.ServerEndedConnectionException
     */
	private void doAllWork() throws ServerEndedConnectionException {
		try {
			// prepareVideoScreen
			releaseResources();
			// Create a Player that captures live video.
			player = Manager.createPlayer("capture://video");
			player.realize();
			videoControl = (VideoControl) player.getControl("VideoControl");
			// videocanvas preparation
			videoCanvas.initControls(videoControl, player);
			videoCanvas.addCommand(Commander.EXIT);
			videoCanvas.addCommand(Commander.STOP_CLIENT);
			videoCanvas.setCommandListener(commandListener);
			player.start();


			if (AUTOSNAPS) {
				do {
					byte[] image;

					try {
						image = videoControl.getSnapshot("encoding=jpeg");
						sendData(image);
						Thread.sleep(1000);
					} catch (MediaException ex) {
						System.err.println("MediaException: " + ex.getMessage());
					} catch (InterruptedException ex) {
						System.err.println("InterruptedException: " + ex.getMessage());
					}
				} while (true);
			} else {
				videoCanvas.addCommand(Commander.SEND_SNAPSHOT);
			}


		} catch (Exception e) {
			e.printStackTrace();
		}
	}

    /**
     * Odesle snapshot serveru.
     */
	public void sendSnapshot() {
		(new SnapshotSender()).start();
	}

	private class SnapshotSender extends Thread {

		public SnapshotSender() {
		}

		public void run() {
			try {
				byte[] image = videoControl.getSnapshot("encoding=jpeg");
				sendData(image);
			} catch (MediaException ex) {
				System.err.println("MediaException: " + ex.getMessage());
			}

		}
	}

	private class CameraThread extends Thread {

		public CameraThread() {
		}

		public void run() {
			try {
				doAllWork();
			} catch (ServerEndedConnectionException ex) {
				terminateClient();
			}
		}
	}
}
